package com.htstar.ovms.device.util;


import java.io.*;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.*;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.htstar.ovms.common.core.util.OvmDateUtil;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

/**
 * 功能: poi导出excel工具类
 */
public class PoiExcelUtil {

    /**
     * 合并单元格处理,获取合并行
     *
     * @param sheet
     * @return List<CellRangeAddress>
     */
    public static List<CellRangeAddress> getCombineCell(Sheet sheet) {
        List<CellRangeAddress> list = new ArrayList<CellRangeAddress>();
        // 获得一个 sheet 中合并单元格的数量
        int sheetmergerCount = sheet.getNumMergedRegions();
        // 遍历所有的合并单元格
        for (int i = 0; i < sheetmergerCount; i++) {
            // 获得合并单元格保存进list中
            CellRangeAddress ca = sheet.getMergedRegion(i);
            list.add(ca);
        }
        return list;
    }

    public static int getRowNum(List<CellRangeAddress> listCombineCell, Cell cell, Sheet sheet) {
        int xr = 0;
        int firstC = 0;
        int lastC = 0;
        int firstR = 0;
        int lastR = 0;
        for (CellRangeAddress ca : listCombineCell) {
            // 获得合并单元格的起始行, 结束行, 起始列, 结束列
            firstC = ca.getFirstColumn();
            lastC = ca.getLastColumn();
            firstR = ca.getFirstRow();
            lastR = ca.getLastRow();
            if (cell.getRowIndex() >= firstR && cell.getRowIndex() <= lastR) {
                if (cell.getColumnIndex() >= firstC && cell.getColumnIndex() <= lastC) {
                    xr = lastR;
                }
            }

        }
        return xr;

    }

    /**
     * 判断指定的单元格是否是合并单元格
     *
     * @param sheet
     * @param row
     *            行下标
     * @param column
     *            列下标
     * @return
     */
    public static boolean isMergedRegion(Sheet sheet, int row, int column) {
        int sheetMergeCount = sheet.getNumMergedRegions();
        for (int i = 0; i < sheetMergeCount; i++) {
            CellRangeAddress range = sheet.getMergedRegion(i);
            int firstColumn = range.getFirstColumn();
            int lastColumn = range.getLastColumn();
            int firstRow = range.getFirstRow();
            int lastRow = range.getLastRow();
            if (row >= firstRow && row <= lastRow) {
                if (column >= firstColumn && column <= lastColumn) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 如果需要合并的话，就合并
     */
    public static void mergeIfNeed(ExcelWriter writer, int firstRow, int lastRow, int firstColumn, int lastColumn, Object content) {
        if (lastRow - firstRow > 0 || lastColumn - firstColumn > 0) {
            writer.merge(firstRow, lastRow, firstColumn, lastColumn, content, false);
        } else {
            writer.writeCellValue(firstColumn, firstRow, content);
        }

    }
    public static void writeExcel(HttpServletResponse response, ExcelWriter writer) {


        OutputStream servletOutputStream = null;
        try {
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + new String(URLEncoder.encode(
                    "定位信息" + OvmDateUtil.getCstNowDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))
                    , "UTF-8").getBytes("UTF-8"), "ISO8859-1") + ".xlsx");
            servletOutputStream = response.getOutputStream();
            writer.flush(servletOutputStream, true);
        } catch (IOException e) {

        } finally {
            writer.close();
            IoUtil.close(servletOutputStream);
        }
        return;
    }
    public static void writeExcel(String filename, ExcelWriter writer, HttpServletResponse response){
        ServletOutputStream ouputStream = null;
        try {
            filename = new String(filename.getBytes("UTF-8"), "ISO-8859-1");
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-disposition", "attachment;filename=" + filename);
            ouputStream = response.getOutputStream();
            writer.flush(ouputStream);
            ouputStream.flush();
            Runtime.getRuntime().gc();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            writer.close();
            if (null != ouputStream) {
                try {
                    ouputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * 目标输出流
     */
    private OutputStream stream;
    private Map<String,Object> fields;
    private static Map<String, Field> fieldMap = new HashMap<>();
    /**
     * 表头
     */
    public  PoiExcelUtil(HttpServletResponse response, Map<String,Object> fields, String fileName, Class<?> clz) throws IOException{
        if(response == null || fields == null || fileName == null || clz == null) {
            throw new IllegalArgumentException();
        }
        getFieldMap(clz,fieldMap);
        this.stream = response.getOutputStream();
        this.fields = fields;
        response.setContentType("application/octet-stream;charset=GBK");
        response.setHeader("Content-Disposition", "attachment;fileName="+ fileName);
        //写表头，生成指定名字的文件，返回客户端
        StringBuilder hb = new StringBuilder();
        for(Map.Entry<String, Object> e : fields.entrySet()) {
            hb.append(e.getValue()+",");
        }
        stream.write(hb.substring(0, hb.length() - 1).getBytes("GBK"));
        stream.flush();
    }

    /**
     * 往表格中插入记录
     */
    public void write(List<Map<String, Object>> data) throws IllegalArgumentException, IllegalAccessException, IOException{
        for(Object o : data){
            StringBuilder sb = new StringBuilder();
            sb.append("\n");
            for(String field : fields.keySet()){
                Field f = fieldMap.get(field);
                f.setAccessible(true);
                Object value = f.get(o);
                if(value == null || StringUtils.isBlank(value.toString())){
                    sb.append(" ,");
                } else if (f.getType() == Date.class) {
                    sb.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value) + ",");
                } else if (f.getType() == DateTime.class) {
                    sb.append(((DateTime)value).toString("yyyy-MM-dd HH:mm:ss") + ",");
                } else {
                    String tmp = value.toString();
                    if(tmp.contains(",")) {
                        tmp = tmp.replace(",", "\",\"");
                    }
                    sb.append(value.toString() + ",");
                }
            }
            stream.write(sb.substring(0, sb.length() - 1).getBytes("GBK"));
            stream.flush();
        }
    }
    public void close() throws IOException{
        stream.close();
    }
    private static <T extends Object> void getFieldMap(Class<T> clz, Map<String, Field> result) {
        for (Field field : clz.getDeclaredFields()) {
            result.put(field.getName(), field);
        }
        if (clz.getSuperclass() != null) {
            getFieldMap(clz.getSuperclass(), result);
        }
    }
}